/**
 * ObjectPool - 对象池管理系统
 * 通过重用对象实例来减少垃圾回收压力，提高游戏性能
 * @class
 */

export interface Poolable {
  /** 重置对象状态，准备重用 */
  reset(): void
  /** 检查对象是否可以回收到池中 */
  canBePooled(): boolean
}

export interface ObjectPoolOptions<T> {
  /** 初始池大小 */
  initialSize?: number
  /** 最大池大小 */
  maxSize?: number
  /** 对象创建工厂函数 */
  createFn: () => T
  /** 对象重置函数（可选，如果对象实现了Poolable接口则不需要） */
  resetFn?: (obj: T) => void
}

/**
 * 通用对象池类
 * @template T 池中对象的类型
 */
export class ObjectPool<T extends Poolable> {
  private pool: T[] = []
  private createFn: () => T
  private resetFn?: (obj: T) => void
  private maxSize: number
  private createdCount: number = 0
  private borrowedCount: number = 0
  private returnedCount: number = 0

  /**
   * 创建对象池
   * @param options - 对象池配置选项
   */
  constructor(options: ObjectPoolOptions<T>) {
    this.createFn = options.createFn
    this.resetFn = options.resetFn
    this.maxSize = options.maxSize || 100
    
    // 预创建初始对象
    const initialSize = options.initialSize || 10
    for (let i = 0; i < initialSize; i++) {
      const obj = this.createFn()
      this.pool.push(obj)
      this.createdCount++
    }
  }

  /**
   * 从池中借用一个对象
   * @returns 可用的对象实例
   */
  borrow(): T {
    let obj: T

    if (this.pool.length > 0) {
      // 从池中取出对象
      obj = this.pool.pop()!
    } else {
      // 池为空，创建新对象
      obj = this.createFn()
      this.createdCount++
    }

    this.borrowedCount++
    return obj
  }

  /**
   * 将对象归还到池中
   * @param obj - 要归还的对象
   */
  return(obj: T): void {
    if (!obj.canBePooled()) {
      return // 对象不能被池化，直接丢弃
    }

    // 重置对象状态
    if (this.resetFn) {
      this.resetFn(obj)
    } else {
      obj.reset()
    }

    // 如果池未满，将对象放回池中
    if (this.pool.length < this.maxSize) {
      this.pool.push(obj)
      this.returnedCount++
    }
    // 如果池已满，让对象被垃圾回收
  }

  /**
   * 批量归还对象
   * @param objects - 要归还的对象数组
   */
  returnBatch(objects: T[]): void {
    for (const obj of objects) {
      this.return(obj)
    }
  }

  /**
   * 清空对象池
   */
  clear(): void {
    this.pool.length = 0
  }

  /**
   * 获取池的当前大小
   * @returns 池中可用对象的数量
   */
  getPoolSize(): number {
    return this.pool.length
  }

  /**
   * 获取池的最大大小
   * @returns 池的最大容量
   */
  getMaxSize(): number {
    return this.maxSize
  }

  /**
   * 设置池的最大大小
   * @param maxSize - 新的最大大小
   */
  setMaxSize(maxSize: number): void {
    this.maxSize = Math.max(0, maxSize)
    
    // 如果当前池大小超过新的最大值，移除多余对象
    while (this.pool.length > this.maxSize) {
      this.pool.pop()
    }
  }

  /**
   * 预热池，创建指定数量的对象
   * @param count - 要预创建的对象数量
   */
  warmUp(count: number): void {
    const targetSize = Math.min(count, this.maxSize)
    
    while (this.pool.length < targetSize) {
      const obj = this.createFn()
      this.pool.push(obj)
      this.createdCount++
    }
  }

  /**
   * 获取池的统计信息
   * @returns 包含各种统计数据的对象
   */
  getStats(): {
    poolSize: number
    maxSize: number
    createdCount: number
    borrowedCount: number
    returnedCount: number
    hitRate: number
  } {
    const hitRate = this.borrowedCount > 0 
      ? (this.returnedCount / this.borrowedCount) * 100 
      : 0

    return {
      poolSize: this.pool.length,
      maxSize: this.maxSize,
      createdCount: this.createdCount,
      borrowedCount: this.borrowedCount,
      returnedCount: this.returnedCount,
      hitRate: Math.round(hitRate * 100) / 100
    }
  }

  /**
   * 重置统计信息
   */
  resetStats(): void {
    this.createdCount = 0
    this.borrowedCount = 0
    this.returnedCount = 0
  }
}

/**
 * 对象池管理器 - 管理多个对象池
 */
export class ObjectPoolManager {
  private pools: Map<string, ObjectPool<any>> = new Map()

  /**
   * 注册一个对象池
   * @param name - 池的名称
   * @param pool - 对象池实例
   */
  registerPool<T extends Poolable>(name: string, pool: ObjectPool<T>): void {
    this.pools.set(name, pool)
  }

  /**
   * 获取指定名称的对象池
   * @param name - 池的名称
   * @returns 对象池实例，如果不存在则返回undefined
   */
  getPool<T extends Poolable>(name: string): ObjectPool<T> | undefined {
    return this.pools.get(name)
  }

  /**
   * 从指定池中借用对象
   * @param poolName - 池的名称
   * @returns 借用的对象，如果池不存在则返回undefined
   */
  borrow<T extends Poolable>(poolName: string): T | undefined {
    const pool = this.pools.get(poolName)
    return pool ? pool.borrow() : undefined
  }

  /**
   * 将对象归还到指定池
   * @param poolName - 池的名称
   * @param obj - 要归还的对象
   */
  return<T extends Poolable>(poolName: string, obj: T): void {
    const pool = this.pools.get(poolName)
    if (pool) {
      pool.return(obj)
    }
  }

  /**
   * 清空所有对象池
   */
  clearAll(): void {
    for (const pool of this.pools.values()) {
      pool.clear()
    }
  }

  /**
   * 预热所有对象池
   * @param count - 每个池要预创建的对象数量
   */
  warmUpAll(count: number): void {
    for (const pool of this.pools.values()) {
      pool.warmUp(count)
    }
  }

  /**
   * 获取所有池的统计信息
   * @returns 包含所有池统计信息的对象
   */
  getAllStats(): Record<string, any> {
    const stats: Record<string, any> = {}
    
    for (const [name, pool] of this.pools) {
      stats[name] = pool.getStats()
    }
    
    return stats
  }

  /**
   * 获取池的数量
   * @returns 注册的池数量
   */
  getPoolCount(): number {
    return this.pools.size
  }

  /**
   * 移除指定的对象池
   * @param name - 要移除的池名称
   */
  removePool(name: string): void {
    const pool = this.pools.get(name)
    if (pool) {
      pool.clear()
      this.pools.delete(name)
    }
  }

  /**
   * 检查是否存在指定名称的池
   * @param name - 池的名称
   * @returns 如果池存在返回true，否则返回false
   */
  hasPool(name: string): boolean {
    return this.pools.has(name)
  }
}

// 全局对象池管理器实例
export const globalPoolManager = new ObjectPoolManager()